/**
* 给应用层直接使用的日志接口
*/

#ifndef _LOG4APP_H_
#define _LOG4APP_H_

#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif

// 使用方法：
// #include "log.h"                      // 1. 包含日志实现头文件
// #define LOGTAG   "MODNAME"            // 2. 定义模块日志标签
// #define LOGLEVEL LOG_ERR              // 3. 定义模块日志级别（模块内低于这个级别或“全局级别”的不会输出）
// #include "log4app.h"                  // 4. 包含日志应用头文件
// logger_t* _logger = NULL;             // 5.1 (在日志管理程序中)定义全局使用的默认日志指针 _logger
// static logger_t* _logger = NULL;      // 5.2 如果只在当前 C 模块中使用，则可定义一个 static _logger
// _logger = logger_create(name);	     // 6. 在使用日志前，通过 logger_create()/logger_get() 创建命名日志或获取已有日志
// log.d("xxx\n");	                     // 7. 使用日志
//
// 注意: 整个系统中必须且只能有一个模块负责管理系统中要使用的全局日志，包括：
// 1) 通过 logger_get(NULL) 获取默认日志，或通过 logger_create(name) 创建一个自定义的命名日志
// 2) 为日志添加一些 writer，比如: logger_add_stdout(), logger_add_rolling_file() 等
// 3) 为日志设置输出级别 logger_set_level()。这个级别是“全局级别”，低于这个级别的日志不会输出
//
// 具体如何获取到 logger_get() 函数，要看 logger_get() 函数在哪里：
// 1) logger_get() 在源代码里，与应用程序一起编译，声明后可直接使用
// 2) logger_get() 在 lib 里，与应用程序一起 link，声明后可直接使用
// 3) logger_get() 在 dll 里，此时应通过 LoadLibrary() 加载 dll，并通过 GetProcAddress() 并获取它
extern logger_t* _logger;

#ifdef __cplusplus
}
#endif


// 各级别日志输出便捷函数
#define logx(fmt, ...) ((!_logger || (LOGLEVEL < LOG_EMERG  )) ? 0 : _logger->log(_logger, LOG_EMERG,   LOGTAG, fmt, ##__VA_ARGS__))
#define loga(fmt, ...) ((!_logger || (LOGLEVEL < LOG_ALERT  )) ? 0 : _logger->log(_logger, LOG_ALERT,   LOGTAG, fmt, ##__VA_ARGS__))
#define logc(fmt, ...) ((!_logger || (LOGLEVEL < LOG_CRIT   )) ? 0 : _logger->log(_logger, LOG_CRIT,    LOGTAG, fmt, ##__VA_ARGS__))
#define loge(fmt, ...) ((!_logger || (LOGLEVEL < LOG_ERR    )) ? 0 : _logger->log(_logger, LOG_ERR,     LOGTAG, fmt, ##__VA_ARGS__))
#define logw(fmt, ...) ((!_logger || (LOGLEVEL < LOG_WARNING)) ? 0 : _logger->log(_logger, LOG_WARNING, LOGTAG, fmt, ##__VA_ARGS__))
#define logn(fmt, ...) ((!_logger || (LOGLEVEL < LOG_NOTE   )) ? 0 : _logger->log(_logger, LOG_NOTE,    LOGTAG, fmt, ##__VA_ARGS__))
#define logi(fmt, ...) ((!_logger || (LOGLEVEL < LOG_INFO   )) ? 0 : _logger->log(_logger, LOG_INFO,    LOGTAG, fmt, ##__VA_ARGS__))
#define logd(fmt, ...) ((!_logger || (LOGLEVEL < LOG_DEBUG  )) ? 0 : _logger->log(_logger, LOG_DEBUG,   LOGTAG, fmt, ##__VA_ARGS__))

// 不输出调试信息前缀，用于追加式输出，或裸输出
#define log_putc(ch)          ((!_logger) ? 0 : _logger->putc(_logger, ch))
#define log_puts(str)         ((!_logger) ? 0 : _logger->puts(_logger, str))
#define log_printf(fmt, ...)  ((!_logger) ? 0 : _logger->printf(_logger, fmt, ##__VA_ARGS__))
#define log_dumpbin(buf, len) ((!_logger) ? 0 : _logger->dumpbin(_logger, buf, len, 16, true, true))
// 简便输出错误码信息
#define log_errno(str)        ((!_logger) ? 0 : _logger->log(_logger, LOG_ERR, LOGTAG, "%s %s !\n", str, strerror(errno)))

#ifdef __WIN32
#include "utils.h"
// 输出最后一次调用的错误信息
#define log_lasterr(str)      ((!_logger) ? 0 : _logger->log(_logger, LOG_ERR, LOGTAG, "%s %s !\n", str, get_windows_error_msg()))
#endif // __WIN32

// 如果 err != STD_ERR_OK，则打印日志 logfmt, ... 并返回错误码 err
#define retonerr(err, logfmt, ...) if(err) { loge(logfmt, ##__VA_ARGS__); return err; }


#endif //_LOG4APP_H_
